<?php

namespace houze;

use houze\Console;
use houze\SystemTips as Tips;
use Workerman\Worker;

class App extends Console{
    private static $instance = null;
    private function __construct(){}
    private function __clone(){}

    /**
     * 配置项 
    */
    protected $config;
    /**
     * 指令参数集
    */
    private $_argv;
    /**
     * 支持的服务类型
    */
    protected $_server_command = [
        'http',
        'websocket',
        'rpc',
        'tcp'
    ];
    /**
     * 启动的服务参数
    */
    protected $_server_start = [
        'action' => null, // 指令集
        'server' => null, // 启动服务类型
        'option' => null, // 其余参数
    ];

    /**
     * 实例化对象方法，供外部获得唯一的对象
    */
    public static function run(){
        if (empty(self::$instance)) {
            self::$instance = new App();
            return self::$instance;
        }
    }

    /**
     * 启动服务
    */
    public function start() {
        // 初始化配置项
        $this->setConfig();
        // 初始化指令参数
        $this->setCommand();
        // 命令分解
        $this->switchCommand();
    }


    //----------------------------------- 命令转发 -----------------------------------
    /**
     * 命令转发
    */
    private function switchCommand() {
        switch ($this->_server_start['action']) {
            // 启动服务
            case 'start':$this->cmdStart();break;
            // 热重启
            case 'reload':$this->cmdReload();break;
            // 查看服务状态
            case 'status':$this->cmdStatus();break;
            // 停止服务
            case 'stop':$this->cmdStop();break;
            // 没有的指令
            default:$this->cmdExtend();break;
        }
    }

    /**
     * 指令 - 启动服务
    */
    private function cmdStart() {
        if (empty($this->_server_start['server'])) {
            return self::exit_error(Tips::CMD_SERVER_MISSING_1);
        }

        if (in_array($this->_server_start['server'], $this->_server_command) == false) {
            return self::exit_error(Tips::CMD_SERVER_MISSING_2 . implode('、', $this->_server_command));
        }

        if ($this->_server_start['option'] && $this->_server_start['option'] != '-d') {
            return self::exit_error(Tips::CMD_SERVER_MISSING_3);
        }

        // 设置默认时区
        date_default_timezone_set(\houze\Config::get('app.default_timezone'));
        // 清空ENV文件
        $this->reloadEnv();
        \houze\StartRecord::clean_env();
        // 载入路由表注册
        require_once BOX_PATH.'route.php';
        // 载入限流器注册
        require_once BOX_PATH.'limit.php';
        // 载入验证器注册
        require_once BOX_PATH.'validate.php';
        // 打印服务详情
        $this->start_yes();
        // 启动服务
        $service = new \houze\Server(); 
        $service->start($this->_server_start['server'], $this->_server_start['option']);
    }
    /**
     * 指令 - 热重启
    */
    private function cmdReload() {
        \Workerman\Worker::stopAll();
        echo '服务已重启' . PHP_EOL;
    }
    /**
     * 指令 - 查看服务状态
    */
    private function cmdStatus() {
        // 打印服务器字幕
        $this->start_yes();

        if (is_file($this->config['worker_pid_file'] )) {
            
            echo "|--------------------------------\033[47;30m Worker进程信息 \033[0m-----------------------------------".PHP_EOL;
            // 读取所有进程，并列出来
            $idsJson = file_get_contents($this->config['worker_pid_file']);
            echo 'Master进程ID：'.$idsJson.PHP_EOL;
        }
    }
    /**
     * 指令 - 停止服务
    */
    private function cmdStop() {
        if (!file_exists($this->config['worker_pid_file'])) {
            return self::exit_error(Tips::CMD_SERVER_MISSING_10.$this->config['worker_pid_file']);
        }
        // 读取主进程ID 
        $idJson = file_get_contents($this->config['worker_pid_file']);  
        // 通知Workerman停止服务
        var_dump(posix_kill(intval($idJson), SIGINT));
    }
   
    /**
     * 指令 - 扩展导入
    */
    private function cmdExtend() {
        // 转发到外部扩展
        $cmd = ucfirst($this->_server_start['action']);
        $file = dirname(__FILE__).DS.'cmd'.DS.$cmd.'.php';
        if (!file_exists($file)) {
            return self::exit_error(Tips::CMD_SERVER_MISSING_9);
        }
        
        $class = "\houze\cmd\\".$cmd;
        $obj = new $class();
        $res = $obj->run($this->_argv);
        unset($obj);
        return $res;
    }
    
    //----------------------------------- 工具箱 -----------------------------------
    /**
     * 初始化配置项
    */
    private function setConfig() {
        $this->config = \houze\Config::get('server');

        $memory_limit = \houze\Config::get('app.memory_limit');
        if ($memory_limit) {
            ini_set('memory_limit', $memory_limit);
        }
    }

    /**
     * 指令切割
    */
    private function setCommand() {
        global $argc, $argv;

        // CMD最多只兼容5个参数
        if ($argc <= 1 || $argc > 6 ) {
            $this->start_action();
            exit;
        }
        
        $this->_argv = $argv;
        $this->_server_start['action'] = $argv[1] ?? null;
        $this->_server_start['server'] = !empty($argv[2]) ? strtolower($argv[2]) : null;
        $this->_server_start['option'] = !empty($argv[3]) ? strtolower($argv[3]) : null;

        // 删除全局变量
        unset($argc);
        unset($argv);
    }

    /**
     * 初始化env环境文件
    */
    private function reloadEnv($status=true) {
        // 创建缓存目录
        if (!file_exists(LOG_PATH)) mkdir(LOG_PATH, 0755);
        $error = LOG_PATH.'error'.DS;
        if (!file_exists($error)) mkdir($error, 0755);
        $sql = LOG_PATH.'sql'.DS;
        if (!file_exists($sql)) mkdir($sql, 0755);
        $view = LOG_PATH.'view'.DS;
        if (!file_exists($view)) mkdir($view, 0755);
        
        // Workerman日志
        file_put_contents($this->config['log_file'], '');
        // 主进程ID
        file_put_contents($this->config['worker_pid_file'], '');
        // MYSQL连接数
        $path = BOX_PATH.'env'.DS.'mysql_pool_num.count';
        file_put_contents($path, '{}');
        // Redis连接数
        $path = BOX_PATH.'env'.DS.'redis_pool_num.count';
        file_put_contents($path, '{}');
        // Memcache连接数
        $path = BOX_PATH.'env'.DS.'memcache_pool_num.count';
        file_put_contents($path, '{}');
        // MongoDb连接数
        $path = BOX_PATH.'env'.DS.'mongodb_pool_num.count';
        file_put_contents($path, '{}');
        // RabbitMQ连接数
        $path = BOX_PATH.'env'.DS.'rabbitmq_pool_num.count';
        file_put_contents($path, '{}');
        // 路由日志
        file_put_contents($this->config['route_file'], '');
    }
}